package com.tengju.bff.interfaces.manage.crm.dashborad.facade;


import com.beust.jcommander.internal.Lists;
import com.google.common.collect.Maps;
import com.tengju.bff.interfaces.manage.crm.dashborad.vo.PerformanceVO;
import com.tengju.bff.interfaces.shared.*;
import com.tengju.data.domain.model.clickhouse.DwdCrmDetailMRepository;
import com.tengju.data.domain.model.clickhouse.DwdUserClubMapRepository;
import com.tengju.data.domain.model.clickhouse.OdsDealerCenterUserBrandProviderRepository;
import com.tengju.data.domain.model.user.StarLevelEnum;
import com.tengju.data.domain.shared.DateUtil;
import com.tengju.motivation.domain.model.performance.PerformanceObjectiveRepository;
import com.tengju.motivation.domain.model.performance.PerformanceObjective;
import com.tengju.motivation.domain.model.performance.PerformanceObjectiveObjectId;
import com.tengju.motivation.domain.model.performance.PerformanceObjectiveTypeEnum;
import com.tengju.motivation.domain.shared.Quarter;
import com.tengju.user.domain.model.sign.StarChangeRecordRepository;
import com.tengju.user.domain.model.user.StarChangeRecord;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author chenhang
 * @Date 2021/3/6
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class PerformanceFacade {

    private final PerformanceObjectiveRepository performanceObjectiveRepository;
    private final DwdCrmDetailMRepository dwdCrmDetailMRepository;
    private final DwdUserClubMapRepository dwdUserClubMapRepository;
    private final OdsDealerCenterUserBrandProviderRepository odsDealerCenterUserBrandProviderRepository;
    private final StarChangeRecordRepository starChangeRecordRepository;


    public PerformanceVO performance(Long clubId, String quarterStr) {
        PerformanceVO performanceVO = new PerformanceVO();
        if (clubId == null || StringUtils.isBlank(quarterStr)) {
            return performanceVO;
        }
        // 饼图集合
        List<SinglePieVO> pieList = Lists.newArrayList();
        // 行数据集合
        List<Map<String, Object>> records = Lists.newArrayList();

        TableVO tableVO = new TableVO();
        tableVO.setHeader(List.of(
                ColumnVO.of("target", "目标", false),
                ColumnVO.of("mainTarget", "总目标", false),
                ColumnVO.of("completed", "已完成", false),
                ColumnVO.of("completionRate", "完成率", false)
        ));
        Quarter quarter = Quarter.of(quarterStr);
        // 绩效目标的配置
        List<PerformanceObjective> performanceObjectiveList = performanceObjectiveRepository
                .getByObjectIdAndType(List.of(new PerformanceObjectiveObjectId(clubId)),
                        PerformanceObjectiveTypeEnum.CLUB,
                        quarter.getFirstMonth(),
                        quarter.getLastMonth());
        Map<String, PerformanceObjective> keyAndTargetMap = performanceObjectiveList.stream()
                .collect(Collectors.toMap(PerformanceObjective::getKey, p -> p));

        // 俱乐部当前季度的总GMV
        BigDecimal sumGMV = dwdCrmDetailMRepository
                .getSumGMV(clubId, quarter.getYearMonthList());
        sumGMV = Optional.ofNullable(sumGMV).orElse(BigDecimal.ZERO);

        // 俱乐部下所有黑卡idCode
        int userBlackCount = dwdUserClubMapRepository.getUserBlackCountByClubId(clubId);

        // 销售额
        salePerformance(keyAndTargetMap, sumGMV, records, pieList);

        // 月人均销售额
        perCapitaSalePerformance(keyAndTargetMap, sumGMV, userBlackCount, records, pieList);

        // 新增经销商
        addDealerPerformance(keyAndTargetMap, clubId, quarter, records, pieList);

        // 新增一星服务商
        addOneStarServiceProviderPerformance(keyAndTargetMap, clubId, quarter, records, pieList);

        tableVO.setRecords(records);
        performanceVO.setTable(tableVO);
        performanceVO.setPieList(pieList);
        return performanceVO;
    }

    private void addOneStarServiceProviderPerformance(
            Map<String, PerformanceObjective> keyAndTargetMap, Long clubId,
            Quarter quarter, List<Map<String, Object>> records, List<SinglePieVO> pieList) {
        PerformanceObjective performanceObjective = keyAndTargetMap
                .get("addOneStarServiceProvider");
        if (null != performanceObjective) {
            Map<Long, List<StarChangeRecord>> idCodeListMap = getUserStarChangeRecordByQuarterMap(quarter);
            List<Long> idCodes = dwdUserClubMapRepository.getIdCodesByClubIdAndIdCode(clubId,
                    new ArrayList<>(idCodeListMap.keySet()));

            int addOneStarServiceProviderCount = getAddOneStarServiceProviderCount(idCodes, idCodeListMap);

            BigDecimal completed = new BigDecimal(addOneStarServiceProviderCount);

            records.add(buildPerformanceRecord(performanceObjective, completed));
            pieList.add(buildPerformancePieVO(performanceObjective, completed));
        }
    }

    private int getAddOneStarServiceProviderCount(List<Long> idCodes, Map<Long, List<StarChangeRecord>> idCodeListMap) {
        int addOneStarServiceProviderCount = 0;
        for (Entry<Long, List<StarChangeRecord>> entry : idCodeListMap.entrySet()) {
            if (idCodes.contains(entry.getKey())) {
                List<StarChangeRecord> list = entry.getValue();
                StarChangeRecord before = list.get(0);
                StarChangeRecord after = list.get(list.size() - 1);
                if (StarLevelEnum.NONE.getCode().equals(before.getBeforeStarLevel())
                        && after.getAfterStarLevel() > before.getBeforeStarLevel()) {
                    // 升级
                    addOneStarServiceProviderCount++;
                }
//                if (StarLevelEnum.NONE.getCode().equals(after.getAfterStarLevel())
//                        && before.getBeforeStarLevel() > after.getAfterStarLevel()) {
//                    // 降级
//                    addOneStarServiceProviderCount--;
//                }
            }
        }
        return addOneStarServiceProviderCount;
    }

    private Map<Long, List<StarChangeRecord>> getUserStarChangeRecordByQuarterMap(
            Quarter quarter) {
        Map<Long, List<StarChangeRecord>> idCodeListMap = Maps.newHashMap();

        // 时间段内所有的变更记录
        List<StarChangeRecord> starChangeRecordList = starChangeRecordRepository
                .getStarChangeRecordList(quarter.getStartTime(), quarter.getEndTime());

        for (StarChangeRecord starChangeRecord : starChangeRecordList) {
            if (idCodeListMap.containsKey(starChangeRecord.getIdCode().getValue())) {
                List<StarChangeRecord> values = idCodeListMap
                        .get(starChangeRecord.getIdCode().getValue());
                values.add(starChangeRecord);
            } else {
                List<StarChangeRecord> values = Lists.newArrayList();
                values.add(starChangeRecord);
                idCodeListMap.put(starChangeRecord.getIdCode().getValue(), values);
            }
        }
        return idCodeListMap;
    }

    /**
     * 俱乐部所选季度新增经销商数的绩效
     *
     * @param keyAndTargetMap 配置的绩效目标
     * @param clubId          俱乐部id
     * @param quarter         季度 2021Q1
     * @param records         行数据集合
     * @param pieList         饼图集合
     */
    private void addDealerPerformance(Map<String, PerformanceObjective> keyAndTargetMap,
                                      Long clubId, Quarter quarter, List<Map<String, Object>> records, List<SinglePieVO> pieList) {
        PerformanceObjective performanceObjective = keyAndTargetMap.get("addDealer");
        if (null != performanceObjective) {
            // 俱乐部季度新增的黑卡数
            Integer addUserBlackCount = odsDealerCenterUserBrandProviderRepository
                    .getAddUserBlackCount(clubId, quarter.getStartTime(), quarter.getEndTime());

            BigDecimal completed = new BigDecimal(addUserBlackCount);

            records.add(buildPerformanceRecord(performanceObjective, completed));
            pieList.add(buildPerformancePieVO(performanceObjective, completed));
        }
    }

    private void perCapitaSalePerformance(Map<String, PerformanceObjective> keyAndTargetMap,
                                          BigDecimal sumGMV, Integer userBlackCount,
                                          List<Map<String, Object>> records, List<SinglePieVO> pieList) {
        PerformanceObjective performanceObjective = keyAndTargetMap.get("perCapitaSale");
        if (null != performanceObjective) {
            Integer monthOfQuarter = DateUtil.getMonthOfQuarter();

            BigDecimal completed = userBlackCount == 0 ? BigDecimal.ZERO :
                    sumGMV.divide(new BigDecimal(userBlackCount), 4, RoundingMode.HALF_UP)
                            .divide(new BigDecimal(monthOfQuarter), 2, RoundingMode.DOWN);

            records.add(buildPerformanceRecord(performanceObjective, completed));
            pieList.add(buildPerformancePieVO(performanceObjective, completed));
        }
    }

    private void salePerformance(Map<String, PerformanceObjective> keyAndTargetMap,
                                 BigDecimal sumGMV, List<Map<String, Object>> records, List<SinglePieVO> pieList) {
        PerformanceObjective performanceObjective = keyAndTargetMap.get("sale");
        if (null != performanceObjective) {
            records.add(buildPerformanceRecord(performanceObjective, sumGMV));
            pieList.add(buildPerformancePieVO(performanceObjective, sumGMV));
        }
    }

    private Map<String, Object> buildPerformanceRecord(PerformanceObjective performanceObjective,
                                                       BigDecimal completed) {
        Map<String, Object> result = Maps.newHashMap();
        result.put("target", performanceObjective.getName());
        Integer mainTarget = performanceObjective.getValue().intValue();
        AmountVO mainTargetAmountVO = new AmountVO(AmountType.THOUSAND, mainTarget);
        result.put("mainTarget", mainTargetAmountVO);
        result.put("completed", new AmountVO(AmountType.THOUSAND, completed));
        BigDecimal completionRate = mainTarget == 0 ? BigDecimal.ONE
                : completed.divide(new BigDecimal(mainTarget), 2, RoundingMode.DOWN);
        if (BigDecimal.ZERO.compareTo(completed) >= 0) {
            completionRate = BigDecimal.ZERO;
        }
        result.put("completionRate", new AmountVO(AmountType.PERCENT_0, completionRate));
        return result;
    }

    private SinglePieVO buildPerformancePieVO(PerformanceObjective performanceObjective,
                                              BigDecimal completed) {
        Integer mainTarget = performanceObjective.getValue().intValue();
        BigDecimal completionRate = mainTarget == 0 ? BigDecimal.ONE
                : completed.divide(new BigDecimal(mainTarget), 2, RoundingMode.DOWN);
        if (BigDecimal.ZERO.compareTo(completed) >= 0) {
            completionRate = BigDecimal.ZERO;
        }
        SinglePieVO singlePieVO = new SinglePieVO();
        singlePieVO.setTitle(performanceObjective.getName());
        singlePieVO.setDesc(performanceObjective.getDesc());
        singlePieVO.setAmountVO(new AmountVO(AmountType.PERCENT_0, completionRate));
        return singlePieVO;
    }
}
